# frozen_string_literal: true

require_relative '../unit_helper'

module Watir
  module Locators
    class Button
      describe SelectorBuilder do
        include LocatorSpecHelper

        let(:selector_builder) { described_class.new(attributes, query_scope) }
        let(:uppercase) { 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ' }
        let(:lowercase) { 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ' }
        let(:default_types) do
          "translate(@type,'#{uppercase}','#{lowercase}')=translate('button','#{uppercase}','#{lowercase}') or " \
            "translate(@type,'#{uppercase}','#{lowercase}')=translate('reset','#{uppercase}','#{lowercase}') or " \
            "translate(@type,'#{uppercase}','#{lowercase}')=translate('submit','#{uppercase}','#{lowercase}') or " \
            "translate(@type,'#{uppercase}','#{lowercase}')=translate('image','#{uppercase}','#{lowercase}')"
        end

        describe '#build' do
          it 'without any arguments' do
            selector = {}
            built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]"}
            expect(selector_builder.build(selector)).to eq built
          end

          context 'with type' do
            it 'false only locates with button without a type' do
              selector = {type: false}
              built = {xpath: ".//*[(local-name()='button' and not(@type))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'true locates button or input with a type' do
              selector = {type: true}
              built = {xpath: ".//*[(local-name()='button' and @type) or " \
                              "(local-name()='input' and (#{default_types}))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'locates input or button element with specified type' do
              selector = {type: 'reset'}
              type = "translate('reset','#{uppercase}','#{lowercase}')"
              built = {xpath: ".//*[(local-name()='button' and " \
                              "translate(@type,'#{uppercase}','#{lowercase}')=#{type}) or " \
                              "(local-name()='input' and (translate(@type,'#{uppercase}','#{lowercase}')=#{type}))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'raises exception when a non-button type input is specified' do
              selector = {type: 'checkbox'}
              msg = 'Button Elements can not be located by input type: checkbox'
              expect { selector_builder.build(selector) }
                .to raise_exception Watir::Exception::LocatorException, msg
            end
          end

          context 'with xpath or css' do
            it 'returns tag name and type to the locator' do
              selector = {xpath: '#disabled_button', tag_name: 'input', type: 'submit'}
              built = {xpath: '#disabled_button', tag_name: 'input', type: 'submit'}
              expect(selector_builder.build(selector)).to eq built
            end
          end

          context 'with text' do
            it 'locates value of input element with String' do
              selector = {text: 'Button'}
              built = {xpath: ".//*[(local-name()='button' and normalize-space()='Button') or " \
                              "(local-name()='input' and (#{default_types}) and @value='Button')]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'locates text of button element with String' do
              selector = {text: 'Button 2'}
              built = {xpath: ".//*[(local-name()='button' and normalize-space()='Button 2') or " \
                              "(local-name()='input' and (#{default_types}) and @value='Button 2')]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'locates value of input element with simple Regexp' do
              selector = {text: /Button/}
              built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), \"Button\")) or " \
                              "(local-name()='input' and (#{default_types}) and contains(@value, \"Button\"))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'locates text of button element with simple Regexp' do
              selector = {text: /Button 2/}
              built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), \"Button 2\")) or " \
                              "(local-name()='input' and (#{default_types}) and contains(@value, \"Button 2\"))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'Simple Regexp for text' do
              selector = {text: /n 2/}
              built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), \"n 2\")) or " \
                              "(local-name()='input' and (#{default_types}) and contains(@value, \"n 2\"))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'Simple Regexp for value' do
              selector = {text: /Prev/}
              built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), \"Prev\")) or " \
                              "(local-name()='input' and (#{default_types}) and contains(@value, \"Prev\"))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'returns complex Regexp to the locator' do
              selector = {text: /^foo$/}
              built = {xpath: ".//*[(local-name()='button' and contains(normalize-space(), \"foo\")) or " \
                              "(local-name()='input' and (#{default_types}) and contains(@value, \"foo\"))]",
                       text: /^foo$/}
              expect(selector_builder.build(selector)).to eq built
            end
          end

          context 'with value' do
            it 'input element value with String' do
              selector = {value: 'Preview'}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              "[normalize-space()='Preview' or @value='Preview']"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'button element value with String' do
              selector = {value: 'button_2'}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              "[normalize-space()='button_2' or @value='button_2']"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'input element value with simple Regexp' do
              selector = {value: /Prev/}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              '[contains(normalize-space(), "Prev") or contains(@value, "Prev")]'}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'button element value with simple Regexp' do
              selector = {value: /on_2/}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              '[contains(normalize-space(), "on_2") or contains(@value, "on_2")]'}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'button element text with String' do
              selector = {value: 'Button 2'}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              "[normalize-space()='Button 2' or @value='Button 2']"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'button element text with simple Regexp' do
              selector = {value: /ton 2/}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              '[contains(normalize-space(), "ton 2") or contains(@value, "ton 2")]'}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'returns complex Regexp to the locator' do
              selector = {value: /^foo$/}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              '[contains(normalize-space(), "foo") or contains(@value, "foo")]', value: /^foo$/}
              expect(selector_builder.build(selector)).to eq built
            end
          end

          context 'with index' do
            it 'positive' do
              selector = {index: 3}
              built = {xpath: "(.//*[(local-name()='button') or (local-name()='input' and (#{default_types}))])[4]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'negative' do
              selector = {index: -4}
              built = {xpath: "(.//*[(local-name()='button') or " \
                              "(local-name()='input' and (#{default_types}))])[last()-3]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'last' do
              selector = {index: -1}
              built = {xpath: "(.//*[(local-name()='button') or " \
                              "(local-name()='input' and (#{default_types}))])[last()]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'does not return index if it is zero' do
              selector = {index: 0}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]"}
              expect(selector_builder.build(selector)).to eq built
            end

            it 'raises exception when index is not an Integer', :skip_after do
              selector = {index: 'foo'}
              msg = /expected one of \[(Integer|Fixnum)\], got "foo":String/
              expect { selector_builder.build(selector) }.to raise_exception TypeError, msg
            end
          end

          context 'with multiple locators' do
            it 'locates using class and attributes' do
              selector = {class: 'image', name: 'new_user_image', src: true}
              built = {xpath: ".//*[(local-name()='button') or (local-name()='input' and (#{default_types}))]" \
                              "[contains(concat(' ', normalize-space(@class), ' '), ' image ')]" \
                              "[@name='new_user_image' and @src]"}
              expect(selector_builder.build(selector)).to eq built
            end
          end
        end
      end
    end
  end
end
